<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;

/**
 * ThinkPHP API模式 应用程序类
 */
class App {
	
	/**
	 * 应用程序初始化
	 * 
	 * @access public
	 * @return void
	 */
	static public function init() {
		// 定义当前请求的系统常量
		define ( 'NOW_TIME', $_SERVER ['REQUEST_TIME'] );
		define ( 'REQUEST_METHOD', $_SERVER ['REQUEST_METHOD'] );
		define ( 'IS_GET', REQUEST_METHOD == 'GET' ? true : false );
		define ( 'IS_POST', REQUEST_METHOD == 'POST' ? true : false );
		define ( 'IS_PUT', REQUEST_METHOD == 'PUT' ? true : false );
		define ( 'IS_DELETE', REQUEST_METHOD == 'DELETE' ? true : false );
		define ( 'IS_AJAX', ((isset ( $_SERVER ['HTTP_X_REQUESTED_WITH'] ) && strtolower ( $_SERVER ['HTTP_X_REQUESTED_WITH'] ) == 'xmlhttprequest') || ! empty ( $_POST [C ( 'VAR_AJAX_SUBMIT' )] ) || ! empty ( $_GET [C ( 'VAR_AJAX_SUBMIT' )] )) ? true : false );
		
		// URL调度
		Dispatcher::dispatch ();
		
		if (C ( 'REQUEST_VARS_FILTER' )) {
			// 全局安全过滤
			array_walk_recursive ( $_GET, 'think_filter' );
			array_walk_recursive ( $_POST, 'think_filter' );
			array_walk_recursive ( $_REQUEST, 'think_filter' );
		}
		
		// 日志目录转换为绝对路径
		C ( 'LOG_PATH', realpath ( LOG_PATH ) . '/' );
		// TMPL_EXCEPTION_FILE 改为绝对地址
		C ( 'TMPL_EXCEPTION_FILE', realpath ( C ( 'TMPL_EXCEPTION_FILE' ) ) );
		return;
	}
	
	/**
	 * 执行应用程序
	 * 
	 * @access public
	 * @return void
	 */
	static public function exec() {
		if (! preg_match ( '/^[A-Za-z](\/|\w)*$/', CONTROLLER_NAME )) { // 安全检测
			$module = false;
		} else {
			// 创建控制器实例
			$module = A ( CONTROLLER_NAME );
		}
		
		if (! $module) {
			// 是否定义Empty控制器
			$module = A ( 'Empty' );
			if (! $module) {
				E ( L ( '_CONTROLLER_NOT_EXIST_' ) . ':' . CONTROLLER_NAME );
			}
		}
		
		// 获取当前操作名 支持动态路由
		$action = ACTION_NAME;
		
		try {
			if (! preg_match ( '/^[A-Za-z](\w)*$/', $action )) {
				// 非法操作
				throw new \ReflectionException ();
			}
			// 执行当前操作
			$method = new \ReflectionMethod ( $module, $action );
			if ($method->isPublic () && ! $method->isStatic ()) {
				$class = new \ReflectionClass ( $module );
				// URL参数绑定检测
				if (C ( 'URL_PARAMS_BIND' ) && $method->getNumberOfParameters () > 0) {
					switch ($_SERVER ['REQUEST_METHOD']) {
						case 'POST' :
							$vars = array_merge ( $_GET, $_POST );
							break;
						case 'PUT' :
							parse_str ( file_get_contents ( 'php://input' ), $vars );
							break;
						default :
							$vars = $_GET;
					}
					$params = $method->getParameters ();
					$paramsBindType = C ( 'URL_PARAMS_BIND_TYPE' );
					foreach ( $params as $param ) {
						$name = $param->getName ();
						if (1 == $paramsBindType && ! empty ( $vars )) {
							$args [] = array_shift ( $vars );
						} elseif (0 == $paramsBindType && isset ( $vars [$name] )) {
							$args [] = $vars [$name];
						} elseif ($param->isDefaultValueAvailable ()) {
							$args [] = $param->getDefaultValue ();
						} else {
							E ( L ( '_PARAM_ERROR_' ) . ':' . $name );
						}
					}
					array_walk_recursive ( $args, 'think_filter' );
					$method->invokeArgs ( $module, $args );
				} else {
					$method->invoke ( $module );
				}
			} else {
				// 操作方法不是Public 抛出异常
				throw new \ReflectionException ();
			}
		} catch ( \ReflectionException $e ) {
			// 方法调用发生异常后 引导到__call方法处理
			$method = new \ReflectionMethod ( $module, '__call' );
			$method->invokeArgs ( $module, array (
					$action,
					'' 
			) );
		}
		return;
	}
	
	/**
	 * 运行应用实例 入口文件使用的快捷方法
	 * 
	 * @access public
	 * @return void
	 */
	static public function run() {
		App::init ();
		// Session初始化
		if (! IS_CLI) {
			session ( C ( 'SESSION_OPTIONS' ) );
		}
		// 记录应用初始化时间
		G ( 'initTime' );
		App::exec ();
		return;
	}
}